package com.android.functionmanagement.util;

import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import com.android.functionmanagement.globle.ConstantGloble;

import android.content.Context;
import android.text.TextUtils;

public class UploadFile {
	private final static String REQUEST_ERROR = "{\"respHead\":{\"respCode\":\"404\",\"respMsg\":\"系统繁忙,请稍候再试\"},\"body\":{}}";
	private final static String REQUEST_ERROR_NETWORK = "{\"respHead\":{\"respCode\":\"400\",\"respMsg\":\"网络未连接,请检测网络!\"},\"body\":{}}";

	public String getResult(String url, File file, HashMap<String, Object> args, Context context) {
			XHttpConnect hc = new XHttpConnect();
			hc.setUrl(url);
			if (file != null) {
//				hc.addHeader(ConstantGloble.TERMINALTYPE, "2");//TODO
//				hc.addHeader(ConstantGloble.VERSION, DeviceUtils.getVersionCode(context)+"");
//				hc.addHeader(ConstantGloble.TRANSTIME,
//						String.valueOf(System.currentTimeMillis()));
				for (Entry<String, Object> entry : args.entrySet()) {
					Object v = entry.getValue();
					String value = v == null ? "" : v.toString();
					hc.addHeader(entry.getKey(), value);
				}
				hc.addFile("file", file);
			}
			try {
				XHttpResponse hr = hc.execute();
				String result = hr.toString();
				if (!TextUtils.isEmpty(result)) {
					return result;
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return REQUEST_ERROR;
	}

	public class XHttpResponse {
		private Map<String, String> headers;

		private int responseCode;

		private String responseMessage;

		private InputStream contentStream;

		private String contentEncoding;

		private String contentType;

		private int contentLength;

		public Map<String, String> getHeaders() {
			return headers;
		}

		public void setHeaders(Map<String, String> headers) {
			this.headers = headers;
		}

		public int getResponseCode() {
			return responseCode;
		}

		public void setResponseCode(int responseCode) {
			this.responseCode = responseCode;
		}

		public String getResponseMessage() {
			return responseMessage;
		}

		public void setResponseMessage(String responseMessage) {
			this.responseMessage = responseMessage;
		}

		public InputStream getContentStream() {
			return contentStream;
		}

		public void setContentStream(InputStream contentStream) {
			this.contentStream = contentStream;
		}

		public String getContentEncoding() {
			return contentEncoding;
		}

		public void setContentEncoding(String contentEncoding) {
			this.contentEncoding = contentEncoding;
		}

		public String getContentType() {
			return contentType;
		}

		public void setContentType(String contentType) {
			this.contentType = contentType;
		}

		public int getContentLength() {
			return contentLength;
		}

		public void setContentLength(int contentLength) {
			this.contentLength = contentLength;
		}

	}

	public class XHttpConnect {

		/**
		 * 二进制参数
		 */
		private final byte[] BINARY_ENCODING = "Content-Transfer-Encoding: binary\r\n\r\n"
				.getBytes();
		/**
		 * 文本参数
		 */
		private final byte[] BIT_ENCODING = "Content-Transfer-Encoding: 8bit\r\n\r\n"
				.getBytes();
		/**
		 * 内容
		 */
		private static final String CONTENT_DISPOSITION = "Content-Disposition: ";
		/**
		 * 类型
		 */
		private static final String CONTENT_TYPE = "Content-Type: ";
		/**
		 * 类型
		 */
		private static final String HEADER_CONTENT_TYPE = "Content-Type";
		private final char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
				.toCharArray();
		/**
		 * 换行
		 */
		private static final String NEW_LINE_STR = "\r\n";
		/**
		 * 字节流参数
		 */
		private static final String TYPE_OCTET_STREAM = "application/octet-stream";
		/**
		 * 文本参数和字符集
		 */
		private static final String TYPE_TEXT_CHARSET = "text/plain; charset=UTF-8";
		/**
		 * 连接超时时间
		 */
		private int connectTimeoutMs = 20000;
		/**
		 * header参数
		 */
		private HashMap<String, String> headers;
		/**
		 * args参数
		 */
		private HashMap<String, String> urlParams;
		/**
		 * 上传文件
		 */
		private HashMap<String, File> fileParams;
		/**
		 * json参数
		 */
		private String jsonParams;
		/**
		 * 分隔符
		 */
		private String mBoundary = null;
		/**
		 * 获取数据超时时间
		 */
		private int readTimeoutMs = 15 * 60 * 1000;
		/**
		 * URL
		 */
		private String url;
		private boolean hasFile;
		private String contentType;

		/**
		 * 生成分隔符
		 */
		private String generateBoundary() {
			final StringBuffer buf = new StringBuffer();
			final Random rand = new Random();
			for (int i = 0; i < 30; i++) {
				buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
			}
			return buf.toString();
		}

		private void addBodyIfExists(HttpURLConnection connection)
				throws IOException {
			connection.setDoOutput(true);
			connection
					.addRequestProperty(HEADER_CONTENT_TYPE, getContentType());
			OutputStream os = connection.getOutputStream();
			try {
				if (!TextUtils.isEmpty(jsonParams)) {
					copyNoClose(
							new ByteArrayInputStream(
									jsonParams.getBytes("utf-8")), os);
				} else if (hasFile) {
					if (urlParams != null) {
						for (Entry<String, String> entry : urlParams.entrySet()) {
							writeToOutputStream(os, entry.getKey(),
									new ByteArrayInputStream(entry.getValue()
											.getBytes()), TYPE_TEXT_CHARSET,
									BIT_ENCODING, "");
						}
					}
					if (fileParams != null) {
						for (Entry<String, File> entry : fileParams.entrySet()) {
							File file = entry.getValue();
							writeToOutputStream(os, entry.getKey(),
									new FileInputStream(file),
									TYPE_OCTET_STREAM, BINARY_ENCODING,
									file.getName());
						}
						// 参数最末尾的结束符
						final String endString = "--" + mBoundary + "--\r\n";
						// 写入结束符
						os.write(endString.getBytes());
					}
				}
			} finally {
				os.close();
			}
		}

		public String getContentType() {
			// 如果contentType没有被自定义，且参数集包含文件，则使用有文件的contentType
			if (hasFile && contentType == null) {
				contentType = "multipart/form-data; boundary=" + mBoundary;
			}
			if (contentType == null) {
				contentType = "application/x-www-form-urlencoded; charset=utf-8";
			}
			return contentType;
		}

		public XHttpResponse execute() throws IOException,
				MalformedURLException

		{
			URL url = new URL(this.url);
			HttpURLConnection connection = (HttpURLConnection) url
					.openConnection();
			connection.setConnectTimeout(connectTimeoutMs);
			connection.setReadTimeout(readTimeoutMs);
			connection.setUseCaches(false);
			connection.setDoInput(true);
			if (headers != null) {
				for (Entry<String, String> entry : headers.entrySet()) {
					connection.addRequestProperty(entry.getKey(),
							entry.getValue());
				}
			}
			connection.setRequestMethod("POST");
			addBodyIfExists(connection);
			XHttpResponse response = new XHttpResponse();
			int responseCode = connection.getResponseCode();
			if (responseCode == -1) {
				throw new IOException(
						"Could not retrieve response code from HttpUrlConnection.");
			}
			response.setResponseCode(responseCode);
			response.setResponseMessage(connection.getResponseMessage());
			// contentStream
			InputStream inputStream;
			try {
				inputStream = connection.getInputStream();
			} catch (IOException ioe) {
				inputStream = connection.getErrorStream();
			}
			response.setContentStream(inputStream);

			response.setContentLength(connection.getContentLength());
			response.setContentEncoding(connection.getContentEncoding());
			response.setContentType(connection.getContentType());
			// header
			Map<String, String> headerMap = new HashMap<String, String>();
			for (Entry<String, List<String>> header : connection
					.getHeaderFields().entrySet()) {
				if (header.getKey() != null) {
					String value = "";
					for (String v : header.getValue()) {
						value += (v + "; ");
					}
					headerMap.put(header.getKey(), value);
				}
			}
			response.setHeaders(headerMap);
			return response;
		}

		public StringBuilder getUrlParams() {
			StringBuilder result = new StringBuilder();
			boolean isFirst = true;
			if (urlParams != null) {
				for (ConcurrentHashMap.Entry<String, String> entry : urlParams
						.entrySet()) {
					if (!isFirst) {
						result.append("&");
					} else {
						result.append("?");
						isFirst = false;
					}
					result.append(entry.getKey());
					result.append("=");
					result.append(entry.getValue());
				}
			}
			return result;
		}

		/**
		 * 参数开头的分隔符
		 * 
		 * @throws IOException
		 */
		private void writeFirstBoundary(OutputStream os) throws IOException {
			os.write(("--" + mBoundary + "\r\n").getBytes());
		}

		/**
		 * 将数据写入到输出流中
		 */
		private void writeToOutputStream(OutputStream os, String paramName,
				InputStream is, String type, byte[] encodingBytes,
				String fileName) {
			try {
				writeFirstBoundary(os);
				os.write((CONTENT_TYPE + type + NEW_LINE_STR).getBytes());
				os.write(getContentDispositionBytes(paramName, fileName));
				os.write(encodingBytes);
				copyNoClose(is, os);
				os.write(NEW_LINE_STR.getBytes());
			} catch (final IOException e) {
				e.printStackTrace();
			} finally {
				close(is);
			}
		}

		/**
		 * 关闭流
		 * 
		 * @param closeable
		 */
		public void close(Closeable closeable) {
			if (closeable != null) {
				try {
					closeable.close();
				} catch (IOException e) {
				}
			}
		}

		private byte[] getContentDispositionBytes(String paramName,
				String fileName) {
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.append("--").append(mBoundary).append("\r\n")
					.append(CONTENT_DISPOSITION).append("form-data; name=\"")
					.append(paramName).append("\"");
			if (!TextUtils.isEmpty(fileName)) {
				stringBuilder.append("; filename=\"").append(fileName)
						.append("\"");
			}
			return stringBuilder.append(NEW_LINE_STR).toString().getBytes();
		}

		public void addHeader(String key, String value) {
			if (this.headers == null) {
				this.headers = new HashMap<String, String>();
			}
			this.headers.put(key, value);
		}

		public void addParams(String key, String value) {
			if (this.urlParams == null) {
				this.urlParams = new HashMap<String, String>();
			}
			this.urlParams.put(key, value);
		}

		public void addFile(String key, File file) {
			this.mBoundary = generateBoundary();
			this.hasFile = true;
			if (this.fileParams == null) {
				this.fileParams = new HashMap<String, File>();
			}
			this.fileParams.put(key, file);
		}

		public void setConnectTimeoutMs(int connectTimeoutMs) {
			this.connectTimeoutMs = connectTimeoutMs;
		}

		public void setJsonParams(String jsonParams) {
			this.jsonParams = jsonParams;
			contentType = "application/json; charset=utf-8";
		}

		public void setReadTimeoutMs(int readTimeoutMs) {
			this.readTimeoutMs = readTimeoutMs;
		}

		public void setUrl(String url) {
			this.url = url;
		}
	}

	/**
	 * 拷贝流
	 * 
	 * @param is
	 * @param os
	 */
	public static boolean copyNoClose(InputStream is, OutputStream os) {
		if (is == null || os == null)
			return false;
		int len = -1;
		byte[] buffer = new byte[2048];
		try {
			while ((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
			return true;
		} catch (IOException e) {
		} finally {
		}
		return false;
	}

}
